﻿package com.alstudio.utils.image;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.net.Uri;
import android.provider.CalendarContract.Events;
import android.util.Log;

import com.alstudio.utils.android.net.IoUtils;
import com.alstudio.utils.encode.ALBase64;
import com.alstudio.utils.formater.string.StringUtils;

public class BitmapUtil {

	private static final String THIS = "BitmapUtil";
	// 压缩为原图的2倍
	public static final int DEFAULT_SAMPLE_SIZE_2 = 1;

	/**
	 * 将位图压为base64字符串
	 * 
	 * @param resizedBitmap
	 * @return
	 */
	public static String compressImagebybase64(Bitmap resizedBitmap) {

		ByteArrayOutputStream baos = new ByteArrayOutputStream();

		// alonso 修正resizedBitmap为null时死机的错误
		if (resizedBitmap != null) {
			resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);

			if (baos != null) {
				try {
					baos.close();

				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			System.gc();

			return ALBase64.encode(baos.toByteArray());
		} else {
			return "";
		}

	}

	/**
	 * 将base64字符串转为位图
	 * 
	 * @param imagestring
	 * @return
	 */
	public static Bitmap unCompressImage(String imagestring) {

		byte[] bob = ALBase64.decode(imagestring);
		imagestring = null;
		return BitmapFactory.decodeByteArray(bob, 0, bob.length);

	}

	/**
	 * JPG压缩
	 */
	public static void compressBitmap(Context ctx, Bitmap bitmap, Uri uri) {

		try {
			OutputStream outStream = ctx.getContentResolver().openOutputStream(
					uri);
			bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
			outStream.close();
			System.gc();

		} catch (Exception e) {
			// Log.e("Error", "exception while writing image" + e);
			System.gc();
		}
	}

	/**
	 * JPG压缩
	 */
	public static void compressBitmapPng(Context ctx, Bitmap bitmap, Uri uri) {

		try {
			OutputStream outStream = ctx.getContentResolver().openOutputStream(
					uri);
			bitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
			outStream.close();
		} catch (Exception e) {
			// Log.e("Error", "exception while writing image" + e);
		} finally {
			System.gc();
		}
	}

	public static Bitmap rotate(Bitmap b, int degrees) {
		if (degrees != 0 && b != null) {
			Matrix m = new Matrix();
			m.setRotate(degrees, (float) b.getWidth() / 2,
					(float) b.getHeight() / 2);
			try {
				Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(),
						b.getHeight(), m, true);
				if (b != b2) {
					b.recycle(); // Android开发网再次提示Bitmap操作完应该显示的释放
					b = b2;
				}
			} catch (OutOfMemoryError ex) {
				// Android123建议大家如何出现了内存不足异常，最好return 原始的bitmap对象。.
			}
		}
		return b;
	}

	// 获得圆角图片的方法 10.0f

	public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) {

		if (bitmap == null) {
			return null;
		}

		if (bitmap.getHeight() != bitmap.getWidth()) {
			bitmap = zoomBitmap(bitmap, 140, 140);
		}

		if (roundPx > 80) {
			roundPx = bitmap.getWidth() / 2;
		}

		Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap

		.getHeight(), Config.ARGB_4444);

		Canvas canvas = new Canvas(output);

		final int color = 0xff424242;

		final Paint paint = new Paint();

		final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

		final RectF rectF = new RectF(rect);

		paint.setAntiAlias(true);

		canvas.drawARGB(0, 0, 0, 0);
		canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
				| Paint.FILTER_BITMAP_FLAG));

		paint.setColor(color);

		canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

		paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));

		canvas.drawBitmap(bitmap, rect, rect, paint);
		System.gc();

		return output;

	}

	// 获得圆角图片的方法 10.0f
	public static Bitmap getNewRoundedCornerBitmap(Bitmap bitmap, float roundPx) {

		Bitmap output = null;
		try {
			if (bitmap == null) {
				return null;
			}

			if (bitmap.getHeight() != bitmap.getWidth()) {
				bitmap = zoomBitmap(bitmap, 140, 140);
			}

			if (roundPx > 80) {
				roundPx = bitmap.getWidth() / 2;
			}

			output = Bitmap.createBitmap(bitmap.getWidth(), bitmap

			.getHeight(), Config.ARGB_8888);

			Canvas canvas = new Canvas(output);

			final int color = 0xff424242;

			final Paint paint = new Paint();

			final Rect rect = new Rect(0, 0, bitmap.getWidth(),
					bitmap.getHeight());

			final RectF rectF = new RectF(rect);

			paint.setAntiAlias(true);

			canvas.drawARGB(0, 0, 0, 0);
			canvas.setDrawFilter(new PaintFlagsDrawFilter(0,
					Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));

			paint.setColor(color);

			canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

			paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));

			canvas.drawBitmap(bitmap, rect, rect, paint);

			System.gc();
		} catch (OutOfMemoryError e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return output;

	}

	/**
	 * 得到指定长宽图片的方法
	 * 
	 * @param bitmap
	 * @param w
	 * @param h
	 * @return
	 */
	public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
		int width = bitmap.getWidth();
		int height = bitmap.getHeight();
		Matrix matrix = new Matrix();
		float scaleWidht = ((float) w / width);
		float scaleHeight = ((float) h / height);
		matrix.postScale(scaleWidht, scaleHeight);
		Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height,
				matrix, true);
		System.gc();
		return newbmp;
	}

	/**
	 * 得到指定长宽图片的方法
	 * 
	 * @param bitmap
	 * @param w
	 * @param h
	 * @return
	 */
	public static Bitmap zoomBitmap(String filePath, int w, int h) {

		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;

		Bitmap bitmap = null;
		File dst = new File(filePath);

		int bmWidth = 0, bmHeight = 0;

		if (null != dst && dst.exists()) {
			BitmapFactory.Options opts = null;
			if (w > 0 && h > 0) {
				opts = new BitmapFactory.Options();
				opts.inJustDecodeBounds = true;
				BitmapFactory.decodeFile(dst.getPath(), opts);
				// 计算图片缩放比例
				final int minSideLength = Math.min(w, h);
				opts.inSampleSize = computeSampleSize(opts, minSideLength, w
						* h);
				opts.inJustDecodeBounds = false;
				opts.inInputShareable = true;
				opts.inPurgeable = true;
			}
			try {
				bitmap = BitmapFactory.decodeFile(dst.getPath(), opts);
			} catch (Exception e) {
				e.printStackTrace();
				System.gc();
				return null;
			}
		}

		if (bitmap == null) {
			return null;
		}

		if (w == 0) {
			return bitmap;
		}

		// 原图都与要求的大小一致了，直接返回
		if ((bmWidth == w) && (bmHeight == h)) {
			return bitmap;
		}

		int width = bitmap.getWidth();
		int height = bitmap.getHeight();
		Matrix matrix = new Matrix();
		float scaleWidht = ((float) w / width);
		float scaleHeight = ((float) h / height);
		matrix.postScale(scaleWidht, scaleHeight);
		Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height,
				matrix, true);
		System.gc();
		return newbmp;
	}

	public static boolean isBitmapWidthGreaterThanHeight(String filePath) {

		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;

		Bitmap bitmap = null;
		File dst = new File(filePath);

		if (null != dst && dst.exists()) {
			try {
				bitmap = BitmapFactory.decodeFile(dst.getPath(), options);
			} catch (Exception e) {
				e.printStackTrace();
				System.gc();
				return false;
			}
		}

		if (bitmap == null) {
			return false;
		}

		int w = 0, h = 0;
		w = bitmap.getWidth();
		h = bitmap.getHeight();

		if (w > h) {
			return true;
		} else {
			return false;
		}
	}

	public static boolean isBitmapSmallerThanRequest(String filePath,
			int requestW, int requestH) {
		boolean result = false;

		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;

		Bitmap bitmap = null;
		File dst = new File(filePath);

		if (null != dst && dst.exists()) {
			try {
				bitmap = BitmapFactory.decodeFile(dst.getPath(), options);
			} catch (Exception e) {
				e.printStackTrace();
				System.gc();
				return false;
			}
		}

		if (bitmap == null) {
			return false;
		}

		int w = 0, h = 0;
		w = bitmap.getWidth();
		h = bitmap.getHeight();

		if (w < requestW || h < requestH) {
			return true;
		}

		return result;
	}

	public static int computeSampleSize(BitmapFactory.Options options,
			int minSideLength, int maxNumOfPixels) {
		int initialSize = computeInitialSampleSize(options, minSideLength,
				maxNumOfPixels);

		int roundedSize;
		if (initialSize <= 8) {
			roundedSize = 1;
			while (roundedSize < initialSize) {
				roundedSize <<= 1;
			}
		} else {
			roundedSize = (initialSize + 7) / 8 * 8;
		}

		System.gc();
		return roundedSize;
	}

	private static int computeInitialSampleSize(BitmapFactory.Options options,
			int minSideLength, int maxNumOfPixels) {
		double w = options.outWidth;
		double h = options.outHeight;

		int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math
				.sqrt(w * h / maxNumOfPixels));
		int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(
				Math.floor(w / minSideLength), Math.floor(h / minSideLength));

		if (upperBound < lowerBound) {
			// return the larger one when there is no overlapping zone.
			return lowerBound;
		}

		if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
			return 1;
		} else if (minSideLength == -1) {
			return lowerBound;
		} else {
			return upperBound;
		}
	}

//	public static Bitmap decodeResource(Resources res, int id, int sampleSize) {
//		Bitmap bm = null;
//		BitmapFactory.Options opts = new BitmapFactory.Options();
//		opts.inSampleSize = sampleSize; // 这个的值压缩的倍数（2的整数倍），数值越小，压缩率越小，图片越清晰
//		// 返回原图解码之后的bitmap对象
//		// bm = BitmapFactory.decodeResource(res, id, opts);
//		bm = readBitMap(App.ctx, id);
//		return bm;
//	}
//
//	public static Bitmap decodeFile(String path, int sampleSize) {
//		Bitmap bm = null;
//		BitmapFactory.Options opts = new BitmapFactory.Options();
//
//		opts.inJustDecodeBounds = true;
//
//		BitmapFactory.decodeFile(path, opts);
//		opts.inJustDecodeBounds = false;
//
//		int inSs = computeSampleSize(opts, App.screen_width, App.screen_width
//				* App.screen_width);
//		opts.inSampleSize = inSs; // 这个的值压缩的倍数（2的整数倍），数值越小，压缩率越小，图片越清晰
//		Mylog.e(THIS, "获取压缩率为" + inSs + "的图片,path is " + path);
//		// 返回原图解码之后的bitmap对象
//		// bm = BitmapFactory.decodeResource(res, id, opts);
//		// bm = BitmapFactory.decodeFile(path, opts);
//		try {
//			InputStream is = new FileInputStream(path);
//			bm = BitmapFactory.decodeStream(is, null, opts);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//
//		// 增加当解码失败 则删除图片处理
//		if (bm == null) {
//			File file = new File(path);
//			if (file.exists()) {
//				file.delete();
//			}
//		}
//
//		return bm;
//	}

	public static Bitmap readBitMap(Context context, int resId) {
		BitmapFactory.Options opt = new BitmapFactory.Options();
		opt.inPreferredConfig = Bitmap.Config.RGB_565;
		opt.inPurgeable = true;
		opt.inInputShareable = true;
		// 获取资源图片
		InputStream is = context.getResources().openRawResource(resId);
		return BitmapFactory.decodeStream(is, null, opt);
	}

//	public static Bitmap readBitMap(int resId) {
//		BitmapFactory.Options opt = new BitmapFactory.Options();
//		opt.inPreferredConfig = Bitmap.Config.RGB_565;
//		opt.inPurgeable = true;
//		opt.inInputShareable = true;
//		// 获取资源图片
//		InputStream is = App.ctx.getResources().openRawResource(resId);
//		return BitmapFactory.decodeStream(is, null, opt);
//	}

	public static BitmapDrawable createBitmapDrawable(Context context, int resId) {
		BitmapFactory.Options opt = new BitmapFactory.Options();
		opt.inPreferredConfig = Bitmap.Config.RGB_565;
		opt.inPurgeable = true;
		opt.inInputShareable = true;
		// 获取资源图片
		InputStream is = context.getResources().openRawResource(resId);
		Bitmap bitmap = BitmapFactory.decodeStream(is, null, opt);
		BitmapDrawable drawable = new BitmapDrawable(bitmap);
		drawable.setTargetDensity(context.getResources().getDisplayMetrics());
		IoUtils.closeStream(is);
		return drawable;
	}

//	public static BitmapDrawable createBitmapDrawable(int resId) {
//		BitmapFactory.Options opt = new BitmapFactory.Options();
//		opt.inPreferredConfig = Bitmap.Config.RGB_565;
//		opt.inPurgeable = true;
//		opt.inInputShareable = true;
//		// 获取资源图片
//		InputStream is = App.ctx.getResources().openRawResource(resId);
//		Bitmap bitmap = BitmapFactory.decodeStream(is, null, opt);
//		BitmapDrawable drawable = new BitmapDrawable(bitmap);
//		drawable.setTargetDensity(App.ctx.getResources().getDisplayMetrics());
//		IoUtils.closeStream(is);
//		return drawable;
//	}
//
//	public static Drawable createNinePathDrawable(int resId) {
//		InputStream in = App.ctx.getResources().openRawResource(resId);
//		Drawable d = NinePatchDrawable.createFromStream(in, null);
//		System.out.println(d.getMinimumHeight() + ":" + d.getMinimumHeight());
//		return d;
//	}
//
//	public static Bitmap decodeBitmapFromFile(String path, boolean big) {
//		if (big) {
//			return decodeSampledBitmapFromFile(path, App.screen_width,
//					App.screen_width);
//		} else {
//			return decodeSampledBitmapFromFile(path, 80, 80);
//		}
//	}
//
//	public static BitmapDrawable decodeBitmapDrawableFromFile(String path,
//			boolean big) {
//		if (big) {
//			return decodeSampledBitmapDrawableFromFile(path, App.screen_width,
//					App.screen_width);
//		} else {
//			return decodeSampledBitmapDrawableFromFile(path, 80, 80);
//		}
//	}

	public static BitmapDrawable decodeSampledBitmapDrawableFromFile(
			String filename, int reqWidth, int reqHeight) {

		// First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(filename, options);

		// Calculate inSampleSize
		options.inSampleSize = calculateInSampleSize(options, reqWidth,
				reqHeight);

		// Decode bitmap with inSampleSize set
		options.inJustDecodeBounds = false;
		Bitmap bm = null;
		try {
			bm = BitmapFactory.decodeFile(filename, options);
		} catch (OutOfMemoryError e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		BitmapDrawable drawable = null;
		if (bm != null) {
			drawable = new BitmapDrawable(bm);
		}
		return drawable;
	}

	public static Bitmap decodeSampledBitmapFromResource(Resources res, int id,
			int reqWidth, int reqHeight) {

		// First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		// BitmapFactory.decodeFile(filename, options);
		BitmapFactory.decodeResource(res, id);

		// Calculate inSampleSize
		options.inSampleSize = calculateInSampleSize(options, reqWidth,
				reqHeight);

		// Decode bitmap with inSampleSize set
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeResource(res, id, options);
	}

	/**
	 * Decode and sample down a bitmap from a file to the requested width and
	 * height.
	 * 
	 * @param filename
	 *            The full path of the file to decode
	 * @param reqWidth
	 *            The requested width of the resulting bitmap
	 * @param reqHeight
	 *            The requested height of the resulting bitmap
	 * @return A bitmap sampled down from the original with the same aspect
	 *         ratio and dimensions that are equal to or greater than the
	 *         requested width and height
	 */
	public static Bitmap decodeSampledBitmapFromFile(String filename,
			int reqWidth, int reqHeight) {

		// First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(filename, options);

		// Calculate inSampleSize
		options.inSampleSize = calculateInSampleSize(options, reqWidth,
				reqHeight);

		// Decode bitmap with inSampleSize set
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeFile(filename, options);
	}

	public static int calculateInSampleSize(BitmapFactory.Options options,
			int reqWidth, int reqHeight) {
		// Raw height and width of image
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {
			if (width > height) {
				inSampleSize = Math.round((float) height / (float) reqHeight);
			} else {
				inSampleSize = Math.round((float) width / (float) reqWidth);
			}

			// This offers some additional logic in case the image has a strange
			// aspect ratio. For example, a panorama may have a much larger
			// width than height. In these cases the total pixels might still
			// end up being too large to fit comfortably in memory, so we should
			// be more aggressive with sample down the image (=larger
			// inSampleSize).

			final float totalPixels = width * height;

			// Anything more than 2x the requested pixels we'll sample down
			// further.
			final float totalReqPixelsCap = reqWidth * reqHeight * 2;

			while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
				inSampleSize++;
			}
		}
		return inSampleSize;
	}

	public static Bitmap toGrayscale(Bitmap bitmap) {
		ColorMatrix colorMatrix = new ColorMatrix();
		colorMatrix.setSaturation(0);
		ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix);

		Paint paint = new Paint();
		paint.setColorFilter(filter);

		Bitmap result = Bitmap.createBitmap(bitmap.getWidth(),
				bitmap.getHeight(), Config.ARGB_8888);
		Canvas canvas = new Canvas(result);
		canvas.drawBitmap(bitmap, 0, 0, paint);
		// if(bitmap!=null && !bitmap.isRecycled()){
		// bitmap.recycle();
		// }
		return result;
	}

	/**
	 * 出啊如的dir不能以"/"结束
	 * 
	 * @param dir
	 * @param fileId
	 * @return
	 */
	public static Bitmap decodeBitmap(String dir, String fileId) {
		FileInputStreamProvider ip = new FileInputStreamProvider(new File(dir
				+ "/" + fileId));
		Bitmap bm = null;
		InputStream is = null;

		try {
			is = ip.getInputStream();
			// Decode stream
			bm = BitmapFactory.decodeStream(is);

		} catch (OutOfMemoryError localOutOfMemoryError) {
			return null;
		} catch (Exception e) {
			Log.e(THIS, "Unable to decode stream", e);
		} finally {
			IoUtils.closeStream(is);
		}
		return bm;
	}

	interface InputStreamProvider {
		InputStream getInputStream();
	}

	static class FileInputStreamProvider implements InputStreamProvider {
		final File mFile;

		FileInputStreamProvider(File file) {
			mFile = file;
		}

		@Override
		public InputStream getInputStream() {
			try {
				return new FileInputStream(mFile);
			} catch (FileNotFoundException e) {
			}
			return null;
		}
	}

}
